package cn.cena.pay.service.impl;

import cn.cena.basic.Exception.MyException;
import cn.cena.order.domain.OrderPet;
import cn.cena.order.domain.OrderPetDetail;
import cn.cena.order.mapper.OrderPetDetailMapper;
import cn.cena.order.mapper.OrderPetMapper;
import cn.cena.pay.domain.PayAlipayIninfo;
import cn.cena.pay.domain.PayBill;
import cn.cena.pay.domain.PayFlow;
import cn.cena.pay.dto.AlipayNotifyDto;
import cn.cena.pay.mapper.PayAlipayIninfoMapper;
import cn.cena.pay.mapper.PayBillMapper;
import cn.cena.pay.mapper.PayFlowMapper;
import cn.cena.pay.service.IPayService;
import cn.cena.pet.domain.Pet;
import cn.cena.pet.mapper.PetMapper;
import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class PayServiceImpl implements IPayService {

    @Autowired
    private PayAlipayIninfoMapper alipayIninfoMapper;

    @Autowired
    private PayBillMapper payBillMapper;

    @Autowired
    private PayAlipayIninfoMapper ininfoMapper;

    @Autowired
    private PayFlowMapper payFlowMapper;

    @Autowired
    private OrderPetMapper orderPetMapper;

    @Autowired
    private OrderPetDetailMapper orderPetDetailMapper;

    @Autowired
    private PetMapper petMapper;

    /**
     * 支付申请
     * @param orderSn
     */
    @Override
    @Transactional
    public String applyPay(String orderSn) {
        // 验证参数
        if(StringUtils.isEmpty(orderSn)){
            throw new MyException("非法订单号");
        }
        // 查询支付宝配置
        PayAlipayIninfo alipayIninfo = alipayIninfoMapper.findFirst();
        if (alipayIninfo == null){
            throw new MyException("无支付宝配置信息");
        }
        // 查询支付单
        PayBill payBill = payBillMapper.loadByorderSn(orderSn);
        if (payBill == null){
            throw new MyException("非法订单号");
        }
        // 发起支付请求，调用支付宝API
        // 1. 设置参数（全局只需设置一次）
        Factory.setOptions(alipayIninfo.getOptions());
        try {
            // 2. 发起API调用
            String returnUrl = String.format(alipayIninfo.getReturnUrl(),orderSn);
            AlipayTradePagePayResponse response = Factory.Payment.Page()
                    .pay(payBill.getDigest(), payBill.getUnionPaySn(), payBill.getMoney().toString(), returnUrl);
            // 3. 处理响应或异常
            if (ResponseChecker.success(response)) {
                System.out.println("调用成功");
                return response.body;
            } else {
                System.err.println("调用失败");
            }
        } catch (Exception e) {
            System.err.println("调用遭遇异常，原因：" + e.getMessage());
            throw new RuntimeException(e.getMessage(), e);
        }
        return "支付申请失败";
    }

    @Override
    public String alipayNotify(AlipayNotifyDto dto) {

        // 验证签名

        // 将json对象转化成字符串
        String jsonStr = JSON.toJSONString(dto);
        //接收到的所有参数放入一个Map中
        Map<String, String> parameters = JSON.parseObject(jsonStr, Map.class);
        try {
            Boolean verifyNotify = Factory.Payment.Common().verifyNotify(parameters);
            if (!verifyNotify){
                System.out.println("延签失败");
                return "fail";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 验证订单号
        String orderSn = dto.getOut_trade_no();
        if (StringUtils.isEmpty(orderSn)){
            System.out.println("无效的单号");
            return "fail";
        }
        PayBill payBill = payBillMapper.loadByorderSn(orderSn);
        if (payBill == null){
            System.out.println("无效的单号");
            return "fail";
        }
        //* 3.防止支付结果重复处理 ,支付宝会回调N次
        //*                      - 幂等性处理：调用N次和调用1次的结果一样
        if(payBill.getState().intValue() != PayBill.PAY_WAIT){
            //支付已经被处理
            System.out.println("订单号已经被处理...");
            return "success";
        }


        String app_id = dto.getApp_id();

        if (StringUtils.isEmpty(app_id)){
            System.out.println("无效的appId1");
            return "fail";
        }
        PayAlipayIninfo first = ininfoMapper.findFirst();
        if (!first.getAppid().equals(app_id)){
            System.out.println(app_id);
            System.out.println("无效的appId2");
            return "fail";
        }
        // 保存支付流水表t_pay_flow
        PayFlow payFlow = new PayFlow();
        BeanUtils.copyProperties(dto, payFlow);
        payFlowMapper.save(payFlow);
        if (dto.isTradeWait()){
            // 支付中
            return "fail";
        }
         OrderPet orderPet = orderPetMapper.loadByOderSn(orderSn);
        // 查出订单详情
        List<OrderPetDetail> orderPetDetails = orderPetDetailMapper.loadByorderSn(orderSn);
        List<Long> petIds = orderPetDetails.stream()
                .map(detail -> detail.getPetId()).collect(Collectors.toList());
        // 查询所有宠物
        List<Pet> pets = petMapper.findByIds(petIds, Pet.STATE_ONSALE);
        Date date = new Date();
        if (dto.isTradeSuccess()){
            // 支付成功
            payBill.setState(PayBill.PAY_SUCCESS);
            payBill.setLastPayTime(date);
            orderPet.setState(OrderPet.STATE_PAY_SUCCESS);
            System.out.println(orderPet.getState());
        }else if (dto.isTradeExpire()){
            // 支付超时
            payBill.setState(PayBill.PAY_CANCEL);
            payBill.setUpdateTime(date);
            orderPet.setLastUpdateTime(date);
            orderPet.setState(OrderPet.STATE_EXPIRE_CANCEL);
            pets.forEach(pet -> {
                pet.setStoreNum(pet.getStoreNum() + 1);
                petMapper.update(pet);
            });
        }
        payBillMapper.update(payBill);
        orderPetMapper.update(orderPet);
        System.out.println(orderPet);

        return "success";
    }


}
